#pragma once

#include <iostream>
using namespace std;
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <functional>
#include "log.hpp"
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include "ThreadPool.hpp"
#include "Thread.hpp"
#include "Task.hpp"
#include "Mutex.hpp"

namespace Server
{
    class tcpServer;

    class ThreadData
    {
    public:
        ThreadData(tcpServer *self, int sock) : _self(self), _sock(sock)
        {
        }

    public:
        tcpServer *_self;
        int _sock;
    };

    class tcpServer
    {
        // typedef function<void(int)> func_t;

    public:
        tcpServer(const uint16_t &port = 8080) : _listen_sockfd(-1), _port(port)
        {
        }

        // 初始化：打开套接字，并且bind
        void initServer()
        {
            _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_listen_sockfd < 0)
            {
                logMessage(4, "socket errno");
                exit(1);
            }
            logMessage(1, "socket success");

            // 开始bind
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));

            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY; // 0.0.0.0

            int n = bind(_listen_sockfd, (sockaddr *)&local, sizeof(local));
            if (n < 0)
            {
                logMessage(4, "bind errno");
                exit(2);
            }

            // 到这里就是bind成功
            logMessage(1, "bind success");

            // tcp还要设置为监听状态,因为tcp是可连接的，面向字节流的
            if (listen(_listen_sockfd, 5) < 0)
            { // 第2个参数要等后面再理解，这里只要会使用就可以
                logMessage(4, "listen errno");
                exit(3);
            }
            logMessage(1, "listen success");
        }

        // 开始执行：这里要accept
        void start()
        {
            //初始化线程池
            ThreadPool<Task>::getInstance()->run();




            //signal(SIGCHLD, SIG_IGN); // 采用忽略的处理方法等待信号
            // 服务器用来接收信息，并且还要发信息回给客户端
            while (1)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                bzero(&peer, sizeof(peer));

                int sockfd = accept(_listen_sockfd, (sockaddr *)&peer, &len);
                if (sockfd < 0)
                {
                    logMessage(4, "accept errno");
                    continue; // 张三接客失败的话不要退出，而是继续接客
                }
                logMessage(1, "accept success");
                cout << "sockfd: " << sockfd << endl;

                // version 1
                //  由于tcp是面向字节流的，所以我直接使用文件系统的接口就可以完成通信
                // 缺点：不能多个客户端连接一个服务端。
                //  serviceIo(sockfd);
                //  close(sockfd);

                // version 2:多进程版本
                // pid_t id = fork();
                // if (id == 0)
                // {
                //     close(_listen_sockfd);
                //     // if (fork() > 0)
                //     //     exit(0);
                //     serviceIo(sockfd);
                //     close(sockfd);
                //     exit(0);
                // }
                // close(sockfd);

                // pid_t ret = waitpid(id, nullptr, 0);
                // if (ret > 0)
                // {
                //     cout << "wait success" << ret << endl;
                // }

                // version 3:多线程的版本
                // pthread_t tid;
                // ThreadData *td = new ThreadData(this, sockfd);

                // pthread_create(&tid, nullptr, handlerTask, td);


                //version 4:线程池的版本
                //push进去的任务有2个参数，
                ThreadPool<Task>::getInstance()->push(Task(sockfd,serviceIo));

            }
        }

        // static void *handlerTask(void *args)
        // {
        //     ThreadData *ret = static_cast<ThreadData *>(args);
        //     ret->_self->serviceIo(ret->_sock);
        //     close(ret->_sock); // 用完的文件描述符要关闭
        //     delete ret;
        //     return nullptr;
        // }

        

        ~tcpServer()
        {
        }

    private:
        int _listen_sockfd;
        uint16_t _port;
    };
}